#ifndef ATJENIE_PARSER_H
#define ATJENIE_PARSER_H

#include <QObject>
#include <stdint.h>
#include <QTextStream>
#include <QStack>
#include "qextserialport.h"

#define CHANNEL(unChannelNumber)   (1 << unChannelNumber)
#define DISABLE_SCAN                0x07FFF800
#define DISABLE_TIMEOUT             0
#define DISABLE_PING                0
#define DISABLE_AUTOPOLLING         0
#define CHANNEL_AUTOSELECTION       0

#define ATJENIE_MESSAGE_TYPE        0

enum ATJenie_DeviceType
{
    ATJenie_DeviceType_Coordinator = 0,
    ATJenie_DeviceType_Router,
    ATJenie_DeviceType_EndDevice
};

struct AtJenie_NTU
{
    uint64_t u64AddressParent;
    uint64_t u64AddressNode;
    uint8_t u8Depth;
    uint32_t u32PANID;
    uint8_t u8Channel;
};

struct AtJenie_DTS_Header
{
    uint64_t u64AddressSource;
    uint8_t u8SourceChannel;
    uint8_t u8RemoteChannel;
};

struct AtJenie_HardwareEvent
{
    uint8_t u8Source;
    union
    {
        uint32_t u32Data;
        uint32_t u32EventBitmap;
        uint32_t u32ADCValue;
    };
};

enum ATJenie_TypeOfMatch
{
    ATJenie_TypeOfMatch_Any = 0,
    ATJenie_TypeOfMatch_All
};

//Manipulators is a comfortable way to convert data in stream chunk
QTextStream& BinaryArgument(QTextStream& stream, void *pDatam, size_t stDataSize);

class ATJenie_Parser : public QObject
{
    Q_OBJECT

	volatile bool drFlag;
public:
    explicit ATJenie_Parser(QextSerialPort& Port, QObject *parent = 0);

	//! Send reset to AT Jenic
	bool SendReset();

	bool SendCommand(QString Command);
        bool ConfigureATJenie();
        bool CreateNetwork(uint16_t u16PanID,
                           uint8_t u8Channel, uint32_t u32NetAppID,
                           uint8_t u8RestoreContext, uint8_t u8Routing,
                           uint32_t u32ChannelMask = DISABLE_SCAN, uint8_t u8Children = 10,
                           uint8_t u8EndDevices = 8, uint8_t u8Failures = 5,
                           uint32_t u32EndDeviceTimeout = DISABLE_TIMEOUT);
        bool JoinNetwork(ATJenie_DeviceType DeviceType, uint16_t u16PanID,
                           uint8_t u8Channel, uint32_t u32NetAppID,
                           uint8_t u8RestoreContext, uint8_t u8Routing,
                           uint32_t u32ChannelMask = DISABLE_SCAN, uint8_t u8Children = 10,
                           uint8_t u8EndDevices = 8, uint8_t u8Failures = 5,
                           uint32_t u32EndDeviceTimeout = DISABLE_TIMEOUT,
                           uint16_t u16PingPeriod = DISABLE_PING,
                           uint8_t u8CyclesBeforePing = DISABLE_PING,
                           uint32_t u32ScanSleep = 30000,
                           uint32_t u32PollPeriod = DISABLE_AUTOPOLLING,
                           uint8_t u8MaxNumberOfHops = 0);
        bool RegisterServices(uint32_t u32ServiceMask);
        bool SendListOfRequestedServices(uint32_t u32ServiceMask,
                                         ATJenie_TypeOfMatch TypeOfMatch);
        bool Bind(uint8_t u8LocalService, uint64_t u64RemoteNode,
                  uint8_t u8RemoteService);
        bool Unbind(uint8_t u8LocalService, uint64_t u64RemoteNode,
                  uint8_t u8RemoteService);
        bool SendData(uint64_t u64RemoteNode, QByteArray Data, uint8_t Flags = 0);
        bool SendDataToService(uint8_t u8LocalNode, QByteArray Data, uint8_t Flags = 0);
        bool Polling();
        bool Leave();

signals:
    void NewData(uint64_t u64AddressSource, QByteArray Data);
    void NewData(AtJenie_DTS_Header DTS_Header, QByteArray Data);
    void NetworkJoined(AtJenie_NTU NTU);
    void NetworkCreated(AtJenie_NTU NTU);
    void StackReset();
    void ChildJoined(uint64_t u64AddressChild);
    void ChildLeft(uint64_t u64AddressChild);
    void ChildRejected(uint64_t u64AddressChild);
    void RegisterServiceResponse();
    void ServiceRequestResponse(uint64_t u64AddressRomote, uint32_t u32ServiceMask);
    void DataAcknowledgement(bool bService);
    void Polling(uint8_t u8PollStatus);
    void Tunneling(QString sData);
    void DataPacketSend(bool bSuccessful);
    void HardwareEvent(AtJenie_HardwareEvent HardwareEvent);
public slots:
    void ProcessLine();
    void NetworkOk();
    bool WaitForNetwork(int iTimeout = 10000);
private:
    QextSerialPort& Port_;
    QString Buffer_;
    QStack<QString> ResultStack;
    volatile bool bNetworkOk;
    volatile bool bDataOk;
    //bool WaitForAndReadLine(QString& Buffer, int iTimeout);
    bool ConfigureNetwork(uint32_t u32ChannelMask = DISABLE_SCAN, uint8_t u8Children = 10,
                       uint8_t u8EndDevices = 8, uint8_t u8Failures = 5,
                       uint32_t u32EndDeviceTimeout = DISABLE_TIMEOUT);
    bool ConfigureChild(uint16_t u16PingPeriod = DISABLE_PING,
                       uint8_t u8CyclesBeforePing = DISABLE_PING,
                       uint32_t u32ScanSleep = 10000,
                       uint32_t u32PollPeriod = DISABLE_AUTOPOLLING,
                       uint8_t u8MaxNumberOfHops = 0);
    bool Initialize(uint16_t u16PanID,
                    uint8_t u8Channel,
                    uint32_t u32NetAppID,
                    uint8_t u8RestoreContext,
                    uint8_t u8Routing);
    bool StartDevice(ATJenie_DeviceType DeviceType);
    bool WaitForResult(QString& Buffer, int iTimeout);

};

#endif // ATJENIE_PARSER_H
